<?php

if (!defined('COMPILED_DIR')) {
    define('COMPILED_DIR', VAR_DIR . '/compiled');
}

class Adept_Template_ComponentTree
{
    
    protected $template;
    protected $compiledFile;
    protected $compiledClass;
    protected $compiledDir = COMPILED_DIR;
    
    protected $instance;
    
    /**
     * @var Adept_Template_Builder_ComponentTree
     */
    protected $builder;
    /**
     * @var Adept_Template_Compiler_ComponentTree
     */
    protected $compiler;
    /**
     * @var Adept_Template_Parser_Tpl
     */
    protected $parser;
    
    public function __construct($template) 
    {
    	$locator = Adept_Locator_Template::getInstance();
    	try {
    	   $this->template = $locator->locate($template);
    	} catch (Adept_Exception $e) {
    	    throw new Adept_Template_Exception($e->getMessage(), array('template' => $template));
    	}   
    	        
        $nameOnly = basename($this->template);
        
        $this->compiledClass = preg_replace("~[^\w]~", "_", $nameOnly . md5_file($this->template));
        
        $this->compiledFile = $this->compiledDir . '/' . $this->compiledClass . '.php';
        
        $this->builder = new Adept_Template_Builder_ComponentTree();
        $this->compiler = new Adept_Template_Compiler_ComponentTree();
        $this->compiler->setCompiledClass($this->compiledClass);
        $this->parser = new Adept_Template_Parser_Tpl();
    }	

    public function readSource() 
    {
     
    	return file_get_contents($this->template);
    }	
    
    public function writeCompiledCode($code) 
    {
        $fh = fopen($this->compiledFile, "w+");
        fwrite($fh, $code);
        fclose($fh);
    }	
    
    public function compile()
    {
        $source = $this->readSource();
        
        $this->parser->setObserver($this->builder);    
        
        $this->parser->setTemplateName($this->template);
        
        $this->parser->parse($source);
        
        $root = $this->builder->getRoot();
        
        $code = $this->compiler->compile($root);
        
        $this->writeCompiledCode($code);
    }    
    
    public function isCompiled() 
    {
    	return false;
    }	
    
    public function getRoot() 
    {
        if (!$this->isCompiled()) {
            $this->compile();
        }
        
    	include_once($this->compiledFile);
    	
    	$class = $this->compiledClass;
    	
        $this->instance = new $class();
        
        $root = new Adept_Component_Root($this->compiledClass);
        
        $context = Adept_Context::getInstance();
        $context->setRoot($root);
        
        $this->instance->doBody($root, $context);
        
    	return $root;
    }	
    
}
